package lining;
// LineupSlotValidation.aj
//
// Informatics 102 Spring 2012
// Code Example
//
// This aspect implements the slot number validation for our Lineup classs.
// It's not trying to do anything general; it's very specific, intending only
// to affect one class.  Still, there's value in using an aspect to implement
// it, since we can avoid the code duplication that will otherwise result, and
// since we can choose not to include the aspect when we want to compile the
// program without slot validation.
//
// One important thing that we're seeing here for the first time is the
// ability for parameters to be passed into advice.  The job of advice is
// to allow you to affect change on a piece of existing code.  That advice
// sometimes needs to know something about that piece of existing code in
// order to affect the right change.  For example, in this case, we want to
// weave in some code that checks if a slot number is valid.  In order to do
// that, we'll need to know what the slot number is.  The slot number comes
// from the code being modified by this aspect.  So we'll need to carry
// information out of that code and into our aspect.
//
// The mechanism for carrying information into our advice requires two steps:
//
// (1) Information is carried out of a join point and into a pointcut.  Note
//     that when we write pointcuts, they appear to take parameters.  These
//     parameters don't carry information into a pointcut; they carry
//     information out of it.  This allows us to say "Whenever this pointcut
//     matches the execution of a method that takes an int parameter, carry
//     the int value from that method's parameter into the pointcut."
//
// (2) Advice accepts parameters filled in by the information that pointcuts
//     carry.  This allows us to say, "Whenever this advice is used to advise
//     code matched by some pointcut, take the information from the pointcut
//     and pass it into the advice."
//
// This ability for pointcuts to carry information out of affected code and
// into advice enables many things that could not otherwise be done; we'll
// find many uses for it going forward.


public aspect LineupSlotValidation
{
	// There are two kinds of signatures we'll care about: those that
	// accept one slot number and those that accept two.  The reason we
	// need to differentiate between them is that we need each kind of
	// join point to carry different information with it; some will carry
	// the first slot number into the advice and some will carry the second.
	//
	// In our current design, all methods that take one slot number have
	// it as their first argument; all methods that take two slot numbers
	// have them as their first two arguments.  Going out on a limb, we
	// might assume that this design will continue to hold true (though this
	// does represent a bit of a risk), in which case we can just match
	// this pattern to find all the methods without having to explicitly
	// name each one in the pointcut.  So long as our design continues to
	// follow this pattern, our aspect won't need to change even if we
	// decide to add new methods to the Lineup class.
	//
	// The primitive pointcut "args" allows us to carry information out of
	// a piece of code and into a pointcut.  The first pointcut below reads
	// like this, in English:
	//
	/// "The pointcut methodsThatRequireValidationOfOneSlot carries one int
	//   value with it, called slotNumber.  It matches calls to methods in
	//   the Lineup class whose first parameter is an int, regardless of their
	//   return types.  In each case, the value of the method's first argument
	//   becomes the slotNumber value associated with the pointcut, while the
	//   other method's arguments are not relevant."
	//
	// The second pointcut is similar, but it only pulls out the value of the
	// second argument.  (The idea here is that both pointcuts will match
	// methods whose first two arguments are int, so we use the first pointcut
	// to match the first argument and the second to match the second.)

	pointcut methodsThatRequireValidationOfOneSlot(int slotNumber):
		execution(* Lineup.*(int, ..)) && args(slotNumber, ..);

	pointcut methodsThatRequireValidationOfASecondSlot(int slotNumber2):
		execution(* Lineup.*(int, int, ..)) && args(*, slotNumber2, ..);


	// Here, we declare the advice that requires validation on slot numbers
	// passed to methods that require the validation of one slot number.
	// Notice that we pass a parameter to the before advice, and that its
	// name matches the name of the value carried with the
	// methodsThatRequireValidationOfOneSlot pointcut.

	before(int slotNumber):
		methodsThatRequireValidationOfOneSlot(slotNumber)
	{
		requireThatSlotNumberIsValid(slotNumber);
	}
	
	
	before(int slotNumber2):
		methodsThatRequireValidationOfASecondSlot(slotNumber2)
	{
		requireThatSlotNumberIsValid(slotNumber2);
	}

	
	private void requireThatSlotNumberIsValid(int slotNumber)
	{
		if (slotNumber < 1 || slotNumber > 9)
		{
			throw new InvalidSlotNumberException(slotNumber);
		}
	}
}
